package test.driver;

import static org.testng.Assert.fail;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.json.JSONArray;
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;
import org.testng.SkipException;
import org.testng.annotations.Listeners;
import ru.yandex.qatools.allure.annotations.Title;
import test.testcase.dao.JobDao;
import test.testcase.dao.TestCaseDao;
import test.testcase.dao.preurlDao;
import test.testcase.dao.projectDao;
import test.utils.JsonResult;
import test.utils.Mysql;
import test.service.ServiceJob;
import test.service.ServiceProject;
import test.testcase.Project;
import test.testcase.TestCase;
import test.testcase.TestJob;

@Listeners({Base.class}) @SuppressWarnings("unchecked")
public class Base implements ITestListener{
	
	private static Logger logger = Logger.getLogger(Base.class);
	private static Map<String, HashMap<String, String>> urls = new HashMap<>();
	private static TestJob testjob;
	private static Map<String, Integer> testcaseNo = new HashMap<>();
	private static Project project;
	
	@Override
	public void onTestStart(ITestResult result) {
		TestCase testcase = getTestCase(result);
		Map<String, String> testdata = (Map<String, String>) result.getParameters()[1];
		String title = "";
		if (testdata != null && !testdata.isEmpty()) {
    		if (testcaseNo.containsKey(testcase.getCaseid())) {
    			int count = testcaseNo.get(testcase.getCaseid())+1;
    			testcaseNo.remove(testcase.getCaseid());
    			testcaseNo.put(testcase.getCaseid(), count);
			}else {
    			testcaseNo.put(testcase.getCaseid(), 1);
			}
	    	title = "["+testcase.getChannel()+"]["+testcase.getCaseid()+"-"+testcaseNo.get(testcase.getCaseid())+"]"+testcase.getCasename();
		}else {
	    	title = "["+testcase.getChannel()+"]["+testcase.getCaseid()+"]"+testcase.getCasename();
		}
		try {
			Method[] fields = result.getMethod().getInstance().getClass().getDeclaredMethods();
			for(Method field : fields){
		    	if (field.getName().equals(result.getMethod().getMethodName())) {
		    	//动态修改Title注解的值
		    	Title foo = field.getDeclaredAnnotation(Title.class);
		    	if (foo != null) {
		    		InvocationHandler h = Proxy.getInvocationHandler(foo);
			    	// 获取 AnnotationInvocationHandler 的 memberValues 字段
			    	Field hField = h.getClass().getDeclaredField("memberValues");
			    	// 因为这个字段事 private final 修饰，所以要打开权限
			    	hField.setAccessible(true);
			    	// 获取 memberValues
			    	Map<String, String> memberValues = (Map<String, String>) hField.get(h);
			    	// 修改 value 属性值
			    	memberValues.put("value", title);
					logger.info("执行用例：" + title);
			    	break;
				}
		    }
		}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public void onTestSuccess(ITestResult result) {
	}

	@Override
	public void onTestFailure(ITestResult result) {
	}

	@Override
	public void onTestSkipped(ITestResult result) {
	}

	@Override
	public void onTestFailedButWithinSuccessPercentage(ITestResult result) {
	}

	@Override
	public void onStart(ITestContext context) {
		try {
			loadConfig();
			String projectid = context.getCurrentXmlTest().getAllParameters().get("projectid");
			project = ServiceProject.getProject(projectid);
			testjob = ServiceJob.getAnExecutableJob(projectid);
			if (testjob == null) {
				JobDao.addProjectJob(projectid);
				testjob = ServiceJob.getAnExecutableJob(projectid);
			}else if (ServiceJob.getAnExecutingJob(projectid) != null) {
				fail("有其他任务在执行");
			}
			JobDao.startJob(testjob);
			PropertyConfigurator.configure(getResourcesPath()+"log4j.properties");
		} catch (Exception e) {
			e.printStackTrace();
			throw new SkipException(e.getMessage());
		}
	}
	
	public static void loadConfig() {
		initSysConfig();  //加载系统参数
		initUrl();  //加载项目url前缀
	}
	
	public static void initSysConfig() {
		JsonResult result1 = TestCaseDao.readSysConfig();
		JSONArray array = result1.read("data").toJsonArray();
		for(int i=0;i<array.length();i++) {
			if (array.getJSONObject(i).getString("key").equals("is_proxy")) {
				HttpAPI.setIs_proxy(Boolean.valueOf(array.getJSONObject(i).getString("value")));
			}else if (array.getJSONObject(i).getString("key").equals("proxy_url")) {
				HttpAPI.setProxy_url(array.getJSONObject(i).getString("value"));
			}else if (array.getJSONObject(i).getString("key").equals("proxy_port")) {
				if (!array.getJSONObject(i).getString("value").equals("")) {
					HttpAPI.setProxy_port(Integer.valueOf(array.getJSONObject(i).getString("value")));
				}
			}else if (array.getJSONObject(i).getString("key").equals("retryMax")) {
				Retry.retryMax = Integer.valueOf(array.getJSONObject(i).getString("value"));
			}
		}
	}
	
	private static void initUrl() {
		if (urls == null) {
			urls = new HashMap<>();
		}else {
			urls.clear();
		}
		JsonResult result = projectDao.getList();
		JSONArray array = result.read("data").toJsonArray();
		if (array != null && array.length() >= 0) {
			for(int j=0;j<array.length();j++) {
				String projectid = array.getJSONObject(j).getString("id");
				HashMap<String, String> map = new HashMap<>();
				JsonResult result1 = preurlDao.getList(projectid);  //加载项目前缀地址
				JSONArray array1 = result1.read("data").toJsonArray();
				if (array1 != null && array1.length() >= 0) {
					for(int i=0;i<array1.length();i++) {
						map.put(array1.getJSONObject(i).getString("projectname"), array1.getJSONObject(i).getString("url"));
					}
				}
				urls.put(projectid, map);
			}
		}
	}

	@Override
	public void onFinish(ITestContext context) {
		JobDao.endJob(testjob);
		Mysql.close();
	}
	
	/**
	 * 获取资源文件路径
	 * @return
	 */
	public static String getResourcesPath() {
		String path = System.getProperty("user.dir");
		if (path.contains("target")) {
			path = path.replace("/target", "");
		}
		return path+"/src/main/resources/";
	}
	
    public void wait(int seconds) {
    	try {
			Thread.sleep(seconds*1000);
		} catch (InterruptedException e) {
		}
    }

	public static Map<String, HashMap<String, String>> getUrls() {
		return urls;
	}

	public static TestJob getTestjob() {
		return testjob;
	}
	
	public TestCase getTestCase(ITestResult result) {
		try {
			return (TestCase) result.getParameters()[0];
		} catch (Exception e) {
		}
		return null;
	}

	public static Project getProject() {
		return project;
	}

	public static void setProject(Project project) {
		Base.project = project;
	}

}